//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "functional.h"

FC_NAMESPACE_BEGIN


// numeric.h (numeric operations)
//
// iota
// accumulate
// inner_product
// partial_sum
// adjacent_difference



// iota

template <class ForwardIterator, class T>
	void iota( ForwardIterator first, ForwardIterator last, T value )
	{
		while( first != last )
			*first++ = value++;
	}


// accumulate

template <class InputIterator, class T>
	T accumulate( InputIterator first, InputIterator last, T init )
	{
		for( ; first != last; ++first )
			init += *first;
		return init;
	}

template <class InputIterator, class T, class BinaryOperation>
	T accumulate( InputIterator first, InputIterator last, T init, BinaryOperation op )
	{
		for( ; first != last; ++first )
			init = op(init, *first);
		return init;
	}


// inner_product

template <class InputIterator1, class InputIterator2, class T>
	T inner_product( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init )
	{
		for( ; first1 != last1; ++first1, ++first2 )
			init += (*first1 * *first2);
		return init;
	}

template <class InputIterator1, class InputIterator2, class T, class BinaryOperation1, class BinaryOperation2>
	T inner_product( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryOperation1 op1, BinaryOperation2 op2 )
	{
		for( ; first1 != last1; ++first1, ++first2 )
			init = op1(init, op2(*first1, *first2));
		return init;
	}


// partial_sum

template <class InputIterator, class OutputIterator, class BinaryOperation>
	OutputIterator partial_sum( InputIterator first, InputIterator last, OutputIterator result, BinaryOperation op )
	{
		if( FC_LIKELY(first != last) )
		{
			typename iterator_traits<InputIterator>::value_type value(*first);
			*result = value;
			for( ++result; ++first != last; ++result )
			{
				value = op(value, *first);
				*result = value;
			}
		}

		return result;
	}

template <class InputIterator, class OutputIterator>
	OutputIterator partial_sum( InputIterator first, InputIterator last, OutputIterator result )
	{
		return partial_sum( first, last, result,
			plus< typename iterator_traits<InputIterator>::value_type >() );
	}


// adjacent_difference

template <class InputIterator, class OutputIterator, class BinaryOperation>
	OutputIterator adjacent_difference( InputIterator first, InputIterator last, OutputIterator result, BinaryOperation op )
	{
		typedef typename iterator_traits<InputIterator>::value_type value_type;

		if( FC_LIKELY(first != last) )
		{
			value_type value(*first);
			*result = value;

			for( ++result; ++first != last; ++result )
			{
				const value_type temp(*first);
				*result = op(temp, value);
				value = temp;
			}
		}

		return result;
	}

template <class InputIterator, class OutputIterator>
OutputIterator adjacent_difference( InputIterator first, InputIterator last, OutputIterator result )
{
	return adjacent_difference( first, last, result,
		minus< typename iterator_traits<InputIterator>::value_type >() );
}



FC_NAMESPACE_END

